package swym.client;

import com.den_4.inotify_java.*;
import java.io.*;
import java.util.*;

public class Watch implements WatchHelperListener
{
    private final int ADD = 0, REMOVE = 1;    

    private File watchDir;
    private ArrayList<String> modified;
    private ArrayList<WatchListener> listener;
    private VersionChecker verChk;
    private String clientName;
    
    public Watch(File watchDir, String clientName)
    {
        verChk = VersionChecker.getInstance();
        this.clientName = clientName;
        this.watchDir = watchDir;
        scanDirTree(watchDir);
        modified = new ArrayList<String>();
        listener = new ArrayList<WatchListener>();
    }
    
    public File getWatchDirectory()
    {
        return watchDir;        
    }
    
    private void scanDirTree(File dir)
    {
        WatchHelper wh = new WatchHelper(dir);
        wh.addWatchHelperListener(this);

        for(File f : dir.listFiles())
            if(f.isDirectory())
                scanDirTree(f);
    }

    public void addWatchListener(WatchListener l)
    {
        listener.add(l);
    }

    public void removeWatchListener(WatchListener l)
    {
        listener.remove(l);
    }

    private void fireWatchEvent(int type, File file)
    {
        for(WatchListener wl : listener)
            switch(type)
            {
                case REMOVE:
                    wl.fileRemoved(file);break;
                case ADD:
                    wl.fileAdded(file);break;
                default:break;
            }
    }

    private boolean compareModificationDateTime(String filePath)
    {
        String dateTime = verChk.getVersionInformation(filePath)[1];
        String curDateTime = "" + (new File(watchDir,filePath)).lastModified(); 
        
        return curDateTime.equals(dateTime);
    }
    
    private boolean hasBeenModified(File file)
    {
        boolean output = false;
        String fileWatchLoc = file.getAbsolutePath();
        fileWatchLoc.replace(watchDir.getAbsolutePath(),"");
    
        for(String fn : modified)
            output = output || fn.equals(fileWatchLoc);

        return output;
    }

    public void fileModified(File file)
    {
        System.out.println("File Modified: " + file.getAbsolutePath());
        if(!file.isDirectory() && !hasBeenModified(file))
            modified.add(file.getAbsolutePath().replace(watchDir.getAbsolutePath(),""));
    }

    public void fileCreated(File file)
    {
        if(file.isDirectory())
            (new WatchHelper(file)).addWatchHelperListener(this);
        else
        {
	        //tell client to send file to server as fileChunks
            fireWatchEvent(ADD,file);
        }             
        
        System.out.println("File Created: " + file.getAbsolutePath());
    }    

    public void fileDeleted(File file)
    {
        System.out.println("File Deleted: " + file.getAbsolutePath());

        //tell client notify server of delete
        fireWatchEvent(REMOVE,file);
    }

	public void fileClosed(File file)
	{
            boolean mod = false;
            boolean same;
            String[] fileInfo;
            String curDateTime;
            String relFilePath = file.getAbsolutePath().replace(watchDir.getAbsolutePath(),"");
            
            for(String fn : modified)
                    mod = mod || fn.equals(relFilePath);

            if(mod) //remove
                System.out.println("This is a modified file and it has been changed");
            else //remove
                System.out.println("This is a file that has not been modified and is closed.");
            
            if(mod)
            {      
                //tell client to send file to server as fileChunks
                //before telling client check that the verison and update time are different in versionfile and on disk
              
                synchronized(verChk.getFileLock(relFilePath))
                {
                    //compare file information
                    fileInfo = verChk.getVersionInformation(relFilePath);
                    curDateTime = "" + (new File(watchDir,relFilePath)).lastModified(); 
                    same = fileInfo[1] != null && fileInfo[1].equals(curDateTime);
                }
                
                if(!same)
                {
                    fireWatchEvent(ADD,file);
                    //update version file
                    Integer version;
                    if(fileInfo[0] != null)
                        version = Integer.parseInt(fileInfo[0].substring(fileInfo[0].lastIndexOf("-"))) + 1;
                    else
                        version = 0;
                    
                    verChk.setVersionInformation(relFilePath, clientName + "-" + version, curDateTime);
                }       

                modified.remove(relFilePath);			

                System.out.println("Modified File Closed: " + file.getAbsolutePath());		
            } 
	}
	public void fileMetadataChanged(File file){}

    public static void main(String [] args)
    {
        if(args.length > 0)
        {
            File f = new File(args[0]);
            if(f.exists() && f.isDirectory())
                new Watch(f, "unknown");
            else
                System.out.println("Specified directory does not exist.");
        }
        else
            System.out.println("Please specific a directory to watch.");
    }
}
